/*
 * reverse_adapter.cpp
 *
 * 展示“反向适配”：
 *   - 核心逻辑 fetch_user_profile_coro 使用 C++20 协程实现；
 *   - 对外通过 async_fetch_user_profile_cb 暴露传统回调接口；
 *   - 旧代码可以继续以回调方式使用，新代码可直接 co_await 协程。
 *
 * 构建：
 *   g++ -std=c++20 -O2 reverse_adapter.cpp -o reverse_adapter \
 *       -lboost_system -lpthread
 *   ./reverse_adapter
 */

#include <boost/asio.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <iostream>
#include <string>

namespace asio = boost::asio;
using asio::awaitable;
using asio::co_spawn;
using asio::detached;
using asio::use_awaitable;
using boost::system::error_code;
using namespace std::chrono_literals;

// -----------------------------------------------------------------------------
// 真实业务逻辑：协程方式实现。
// -----------------------------------------------------------------------------
awaitable<std::string> fetch_user_profile_coro(std::string user_id) {
    auto executor = co_await asio::this_coro::executor;

    // 模拟耗时 I/O
    asio::steady_timer timer(executor);
    timer.expires_after(200ms);
    co_await timer.async_wait(use_awaitable);

    co_return "profile-data-for:" + user_id;
}

// -----------------------------------------------------------------------------
// 适配器：把协程逻辑包装成回调接口。
// -----------------------------------------------------------------------------
template <class CompletionHandler>
void async_fetch_user_profile_cb(asio::io_context& io,
                                 std::string user_id,
                                 CompletionHandler&& handler) {
    co_spawn(
        io,
        [user_id = std::move(user_id),
         handler = std::forward<CompletionHandler>(handler)]() mutable -> awaitable<void> {
            error_code ec;
            std::string result;

            try {
                result = co_await fetch_user_profile_coro(user_id);
            } catch (const std::exception& ex) {
                ec = error_code{asio::error::operation_aborted};
                std::cerr << "[adapter] exception: " << ex.what() << "\n";
            }

            // 确保回调在协程所在执行器上执行，保持线程安全。
            auto executor = co_await asio::this_coro::executor;
            co_await asio::post(executor, use_awaitable);

            handler(ec, std::move(result));
            co_return;
        },
        detached);
}

// -----------------------------------------------------------------------------
// 旧代码：依旧使用回调接口。
// -----------------------------------------------------------------------------
void legacy_consumer(asio::io_context& io) {
    std::cout << "[legacy] request profile for alice...\n";

    async_fetch_user_profile_cb(
        io,
        "alice",
        [](const error_code& ec, std::string profile) {
            if (ec) {
                std::cerr << "[legacy] error: " << ec.message() << "\n";
                return;
            }
            std::cout << "[legacy] got profile: " << profile << "\n";
        });
}

// -----------------------------------------------------------------------------
// 新代码：直接使用协程接口。
// -----------------------------------------------------------------------------
awaitable<void> modern_consumer() {
    std::cout << "[modern] request profile for bob...\n";

    error_code ec;
    std::string profile;

    try {
        profile = co_await fetch_user_profile_coro("bob");
    } catch (const std::exception& ex) {
        ec = error_code{asio::error::operation_aborted};
        std::cerr << "[modern] exception: " << ex.what() << "\n";
    }

    if (ec) {
        std::cerr << "[modern] error: " << ec.message() << "\n";
        co_return;
    }
    std::cout << "[modern] got profile: " << profile << "\n";
    co_return;
}

// -----------------------------------------------------------------------------
// 主函数：旧接口与新接口并存，复用同一实现。
// -----------------------------------------------------------------------------
int main() {
    asio::io_context io;

    legacy_consumer(io);                       // 回调调用方向
    co_spawn(io, modern_consumer(), detached); // 协程调用方向

    io.run();
    return 0;
}